using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CSharpExtensions.Linq
{

    #region ImmutableTuple
    public sealed class ImmutableTuple<T1,T2>
    {
        public ImmutableTuple(T1 first, T2 second)
        {
            First = first;
            Second = second;
        }
        public readonly T1 First;
        public readonly T2 Second;

        public override bool Equals(object obj)
        {
            var other = obj as ImmutableTuple<T1, T2>;
            return IsEqual(other);
        }
        public override int  GetHashCode()
        {
 	         return 
                 First.Return(_=>_.GetHashCode(),0)^
                 Second.Return(_=>_.GetHashCode(),0);
        }
        public bool IsEqual(ImmutableTuple<T1,T2> other)
        {
            if (other != null)
            {
                var firstEq = First.Return(
                                    _ => _.Equals(other.First),
                                    other.First == null);
                var secondEq = Second.Return(
                                    _ => _.Equals(other.Second),
                                    other.Second == null);
                return firstEq && secondEq;
            }
            return false;
        }
    }
    public sealed class ImmutableTuple<T1, T2, T3>
    {
        public ImmutableTuple(T1 t1, T2 t2, T3 t3)
        {
            Inner = new ImmutableTuple<ImmutableTuple<T1, T2>, T3>(new ImmutableTuple<T1, T2>(t1, t2), t3);
        }
        private readonly ImmutableTuple<ImmutableTuple<T1, T2>, T3> Inner;
        public T1 First
        {
            get
            {
                return Inner.First.First;
            }
        }
        public T2 Second
        {
            get
            {
                return Inner.First.Second;
            }
        }
        public T3 Third
        {
            get
            {
                return Inner.Second;
            }
        }
        public override bool Equals(object obj)
        {
            var other = obj as ImmutableTuple<T1,T2,T3>;
            if (other != null)
            {
                return IsEqual(other);
            }
            return false;
        }
        public override int GetHashCode()
        {
            return Inner.GetHashCode();
        }
        public bool IsEqual(ImmutableTuple<T1, T2, T3> other)
        {
            return Inner.IsEqual(other.Inner);
        }

    }

    public class ImmutableTuple
    {
        public static ImmutableTuple<T1, T2> Create<T1, T2>(T1 first, T2 second)
        {
            return new ImmutableTuple<T1, T2>(first, second);
        }
        public static ImmutableTuple<T1, T2,T3> Create<T1, T2, T3>(T1 first, T2 second, T3 third)
        {
            return new ImmutableTuple<T1, T2, T3>(first, second, third);
        }
        public static bool Equals<T1, T2>(ImmutableTuple<T1, T2> first, ImmutableTuple<T1, T2> second)
        {
            if (first == second)
                return true;
            if (first == null)
                return false;
            return first.IsEqual(second);
        }
    }
    #endregion

}